home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 5
/
Aminet 5 - March 1995.iso
/
Aminet
/
util
/
misc
/
x10ctrl.lha
/
x10ctrl.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-01-21
|
84KB
|
2,330 lines
/* ======================== X10CTRL.C ================================= */
/* (c) 1988, Stephen L. Childress. 818/706-5247
Main Program.
Amiga 500/1000/2000 program to manage the X10 USA, Inc. CP290
computer interface ($35). This device connects to an Amiga (or other computer)
via an RS232 serial port. With this software, the user can establish
on/off/dim events of a specified duration for specific days of the week.
This is done by drawing lines on a graphics screen with the mouse.
Having done so, this event data can be down-loaded to the CP290 box.
From this point, the CP290 will perform the event data forever, without
further help from the Amiga.
This software also enables the user to up-load the event data to the
Amiga, view it on the graphics screen, and save it to disk. Lastly, the
user can issue an immediate X10 command to an X10 module, from the
Amiga keyboard.
Makefile: (Lattice C)
x10ctrl: x10ctrl.o x10struct.o
blink TO x10ctrl FROM lib:c.o x10ctrl.o x10struct.o \
LIB lib:lc.lib lib:amiga.lib
x10ctrl.o: x10ctrl.c x10ctrl.h
lc x10ctrl.c
x10struct.o: x10struct.c x10ctrl.h
lc x10struct.c
*******************************************************/
#include <exec/types.h>
#include <exec/exec.h>
#include <dos.h>
#include <graphics/view.h>
#include <graphics/display.h>
#include <intuition/intuition.h>
#include <devices/serial.h>
#include <stdio.h>
#include "x10ctrl.h"
char * stpchr();
UWORD * ColorTableAddr;
struct ColorMap *ColorMapAddr;
struct ViewPort *ViewPortAddr(), *vpa;
extern USHORT colortable[];
char datafilename[64], scratchbuf[64];
extern struct Gadget /* see X10STRUCT.C */
gadNAME,
gadFROMX10,
gadX10COMMAND,
gadSECURITY,
gadNEWFILE,
gadWEEKEND,
gadWEEKDAYS,
gadSUN,
gadSAT,
gadFRI,
gadTHURS,
gadWED,
gadTUES,
gadMON,
gadSETNAME,
gadDIMUP,
gadDIMDN,
gadOFF,
gadON,
gadX10DATE,
gadTOX10,
gadNEXT,
gadDEL,
gadQUIT,
gadSETBASE,
gadEARLIER,
gadLATER,
gadLONGER,
gadSHORTER;
extern struct IntuiText
savemsgbody,
savemsgyes,
savemsgno,
ynmessage,
yesmsg,
nomsg,
gadNAMEmsg;
extern struct StringInfo nameinfo;
/*** Things related to the serial port: ***/
extern struct MsgPort *CreatePort();
struct IOExtSer IORser; /* Serial port IO request block */
int Serialisopen = 0;
/** beware of changing this! */
int minutesK = 60 / HourSpacing; /* pixels per minute */
#if 0
/* ================================================================= */
/* This table has the time of sunset for the 1st day of each month.
The times are GMT standard time, 24hr notation, e.g., 1800 = 6PM.
Taken from a 1984 almanac. The times are for 30 degrees North Latitude.
*/
SHORT sunsettable[] = {
/* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
1711, 1737, 1800, 1819, 1837, 1856, 1905, 1853, 1822, 1745, 1713, 1700
};
/* Table of corrections, by month, for sunset, to account for Daylight Savings
time. This table assumes Daylight Savings is practiced. */
SHORT dsmonths[] = {
0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0
};
#endif
/* ================================================================= */
struct Events {
USHORT
link,
xstart,
xstop;
UBYTE
devicecode,
days,
command,
dimness,
flags;
} Events[recordlimit+1];
int devicelist[deviceMax+1];
int mousex,
mousey,
xmax,
Devnum,
devicey,
Eventnum = 0,
oldx,
gadPspacing = gadCspacing * charwidth,
infoline = gadline-3,
infowidth = 79 - infocol,
error,
Signalflag,
Changed = 0,
DevAreaY,
infox,
infoy,
Daymask = 0x7f,
BaseHouseCode = 1,
yesyesflag,
verbose = VERBOSE; /* see the .h */
int clas, code;
UBYTE X10cmd[256];
char textbuf[256];
struct Window *sbwindow = NULL;
struct Window *window, *OpenWindow(); /* returns ptr to structure */
struct Screen *screen, *OpenScreen();
struct IntuiMessage *GetMsg(), *Message;
struct IntuitionBase *IntuitionBase;
struct IntuiText intuitext;
char days[8][4] = { {"__"},{"M "},{"Tu"},{"W "},{"Th"},{"F "},{"Sa"},{"Su"} };
char bsr[6][8] = { {"NONE"}, /* 0 these correspond to bsrON, bsrOFF... */
{"NONE"}, /* 1 */
{"ON "}, /* 2 */
{"OFF "}, /* 3 */
{"NONE"}, /* 4 */
{"DIM "} }; /* 5 */
/* This table is indexed 0..n for housecode 1..16 to
yield the X10 version of that housecode. So housecode=2 ('B') = hex E0 */
UBYTE Housecodes[] = { 0x00,
0x60, 0xE0, 0x20, 0xA0,
0x10, 0x90, 0x50, 0xD0,
0x70, 0xF0, 0x30, 0xB0,
0x00, 0x80, 0x40, 0xC0 }; /* see pg 10 of X10 manual */
char devicenames[deviceMax+1][DEVNAMELEN];
struct RastPort *Rport,
*sbRport = NULL;
struct MsgPort *Intuiport;
struct AreaInfo ainfo;
PLANEPTR myplane;
#define TMPRASX 640 /* see AllocRas() herein */
#define TMPRASY 32
struct GfxBase *GfxBase;
APTR Intuimsg; /* see call to GetMsg() herein */
FILE *datafp;
char nwname[] = " Computerized Home Control Manager for the X10 CP290.";
struct NewScreen X10screen =
{
0, 0, SCREENMAXX, SCREENMAXY, /* size of screen */
4, /* depth */
PENTEXT1, CYAN, /* pens */
HIRES | INTERLACE | SPRITES,
CUSTOMSCREEN,
NULL, /* font */
(UBYTE *) nwname,
NULL, /* gadgets */
NULL /* custom bit map */
};
struct NewWindow nw =
{
0,0, /* LeftEdge and TopEdge */
SCREENMAXX, SCREENMAXY, /* Width and Height */
PENTEXT1, BLACK, /* DetailPen and BlockPen */
/* IDCMP Flags with Flags below */
CLOSEWINDOW | REFRESHWINDOW | MOUSEBUTTONS | GADGETUP,
WINDOWDEPTH | WINDOWCLOSE | SMART_REFRESH | ACTIVATE | REPORTMOUSE,
#if 1
&gadQUIT, NULL, /* Gadget and Image pointers */
#else
NULL, NULL, /* Gadget and Image pointers */
#endif
nwname,
NULL, /* Screen ptr null (this screen) */
NULL, /* BitMap pointer */
SCREENMAXX, SCREENMAXY, /* MinWidth and MinHeight */
SCREENMAXX, SCREENMAXY, /* MaxWidth and MaxHeight */
CUSTOMSCREEN /* Type of window */
};
struct NewWindow nw1 =
{
50, 50, /* LeftEdge and TopEdge */
nw1X, nw1Y, /* Width and Height */
PENTEXT1, BLACK, /* DetailPen and BlockPen */
/* IDCMP Flags with Flags below */
CLOSEWINDOW | REFRESHWINDOW | MOUSEBUTTONS | GADGETUP,
WINDOWCLOSE | SMART_REFRESH | ACTIVATE,
&gadNAME, NULL, /* Gadget and Image pointers */
"Please...", /* Title string */
NULL, /* Screen ptr null (this screen) */
NULL, /* BitMap pointer */
nw1X, nw1Y, /* MinWidth and MinHeight */
nw1X, nw1Y, /* MaxWidth and MaxHeight */
CUSTOMSCREEN /* Type of window */
};
struct NewWindow standbywindow =
{
GADx, GADy-8, /* LeftEdge and TopEdge */
640-GADx, 400-GADy+8, /* Width and Height */
GREEN, RED, /* DetailPen and BlockPen */
/* IDCMP Flags with Flags below */
REFRESHWINDOW | MOUSEBUTTONS | GADGETUP,
SMART_REFRESH | ACTIVATE,
NULL, NULL, /* Gadget and Image pointers */
" B-B-B-BUSY - PLEASE WAIT! ",/* Title string */
NULL, /* Screen ptr null (this screen) */
NULL, /* BitMap pointer */
nw1X, nw1Y, /* MinWidth and MinHeight */
nw1X, nw1Y, /* MaxWidth and MaxHeight */
CUSTOMSCREEN /* Type of window */
};
/* ================================================================= */
int
main()
{
register int i, j, more;
int n;
int error, x, x1, days, command, dimness, class, flags;
register char *p;
/***
struct IntuiText *;
struct Gadget *gad;
*/
/*** Open serial port and set baud rate, etc., for the X10 box.
*/
IORser.io_SerFlags |= SERF_SHARED;
if ((error = OpenDevice (SERIALNAME, 0, &IORser, 0)) != 0) {
printf( "Unable to open Serial Device, error=%ld\n", error );
exit(20);
}
i = (int)
(IORser.IOSer.io_Message.mn_ReplyPort = CreatePort("SetSerial", 0));
if (i == NULL) {
printf( "Unable to create port for IO message\n" );
CloseDevice(&IORser);
exit(20);
}
++Serialisopen;
/*** Read serial port control settings. Then change them to
the values appropriate for the X10 box.
*/
IORser.IOSer.io_Command = SDCMD_QUERY;
if (error = DoIO( &IORser ) != 0) {
printf ( "Query status error %ld\n", error);
cleanup();
exit(20);
}
IORser.io_Baud = 600;
IORser.io_StopBits = 1;
IORser.io_WriteLen = 8;
IORser.io_ReadLen = 8;
IORser.io_SerFlags = 0;
IORser.io_SerFlags |= SERF_XDISABLED;
IORser.IOSer.io_Command = SDCMD_SETPARAMS;
if (error = DoIO( &IORser) != 0) {
printf("Serial I/O SETPARAMS error\n");
cleanup();
exit(20);
}
for (i = 1; i <= 16; ++i)
X10cmd[i] = 0xff; /* build X10 cmd header */
infox = infocol * charwidth;
infoy = infoline * charwidth;
purge(); /* erase all events, initialize strings, etc. */
IntuitionBase =
(struct IntuitionBase *) OpenLibrary ("intuition.library", 0);
if (IntuitionBase == NULL) {
printf("Open Intuition failed\n");
exit(50);
}
GfxBase =
(struct GfxBase *) OpenLibrary ("graphics.library", 0);
if (GfxBase == NULL) {
printf("Open graphics failed\n");
exit(50);
}
screen = OpenScreen(&X10screen);
if (screen == NULL) {
printf("OpenScreen failed\n");
exit(50);
}
nw.Screen = screen;
if ((window = OpenWindow(&nw)) == NULL) {
printf("OpenWindow failed\n");
cleanup();
exit(20);
}
Signalflag = 1 << window->UserPort->mp_SigBit;
Intuiport = window->UserPort;
Rport = window->RPort;
/*** vpa = ViewPortAddress(window);
ColorMapAddr = vpa -> ColorMap;
ColorTableAddr = (UWORD *) ColorMapAddr -> ColorTable;
****/
LoadRGB4(ViewPortAddress(window), &colortable[0], 16);
strcpy(datafilename, DATAFILENAME);
top:
purge();
Eventnum = Devnum = 0;
TimeGraticule(); /* create gaticule displays */
hourlines(); /* redraw the hour lines */
info(0); /* setup blank info window in lower right of screen */
setdategadgets(); /* turn off all day-of-week gadgets */
ScreenToFront(screen); /* WB screen requester can push us to the back */
/*** Reload X10 Event data from ASCII disk file. */
reopen0:
p = " Event Data Disk File Name (Click CLOSE gadget if none) ? ";
goto reopen2;
reopen1:
p = " Unable to open file. New Name? ";
reopen2:
if ((i = getfilename(p)) < 0) {
cleanup();
exit(20);
}
if (i == 1)
goto reopen0; /* name strlen == 0 */
if (i == 2)
goto withoutfile; /* user closed the window */
datafp = fopen(datafilename, "r");
if (datafp == NULL)
goto reopen1;
more = 1;
n = 1;
while (more) {
/*** note: the intermediate variables, e.g., x and x1 below, had to
be used as Lattice C did not compute address of (& operator)
correctly for an array of structures (Events[])
***/
i = fscanf(datafp, "%d,%d,%d,%d,%d,%d,%d\n",
&Devnum,
&x,
&x1,
&days,
&command,
&dimness,
&flags );
Events[n].devicecode = Devnum;
Events[n].xstart = x;
Events[n].xstop = x1,
Events[n].days = days;
Events[n].command = command;
Events[n].dimness = dimness;
Events[n].flags = flags;
if (Devnum > 0 && Devnum <= deviceMax) {
i = devicelist[Devnum];
if (i == 0)
devicelist[Devnum] = n;
else {
while (Events[i].link)
i = Events[i].link;
Events[i].link = n;
}
Events[n].link = 0;
++n;
}
else {
--more;
}
}
/*** Now read the names of the X10 devices: A5 is Porch light, etc.
*/
more = 2;
while (more && (feof(datafp) == 0) ) {
if (fgets(textbuf, sizeof(textbuf), datafp) != NULL) {
stcd_i(textbuf, &n); /* Lattice function: ASCII to int */
p = stpchr(textbuf, '"');
if (p != NULL) {
j = strlen(++p) - 2; /* 2 because of closing " and \n */
if (j >= DEVNAMELEN)
j = DEVNAMELEN;
if (j > 0 && n > 0 && n <= deviceMax) /* if valid device no. */
strncpy(&devicenames[n], p, j);
}
}
else
--more;
}
fclose(datafp);
withoutfile:
Eventnum = Devnum = 0;
RenderAllEvents(); /* display graphs for all events */
/* gad = &gadMON;
for (i = 0; i <= 6; ++i) {
intuitext = gad->GadgetText;
intuitext->FrontPen = (UBYTE) ( (~(DAYCOLOR0 + i)) & 15);
gad = gad->NextGadget;
}
******/
/************************ M A I N L O O P ********************/
for ( ;; ) {
/*** Discard queued up mouse messages */
while ( (Message = GetMsg(Intuiport)) != 0)
ReplyMsg(Message);
SetSignal(0, Signalflag);
if ((Message = GetMsg(Intuiport)) == 0) { /*** Get a new mouse message */
Wait(Signalflag);
Message = GetMsg(Intuiport);
}
Intuimsg = (APTR)Message->IAddress; /* for gadgets, points to gadget*/
class = Message->Class;
code = Message->Code;
mousex = window->MouseX;
mousey = window->MouseY;
ReplyMsg(Message);
/* ================================================================= */
Daymask = Events[Eventnum].days;
/*** Process mouse action: Gadget or clicked on a pixel */
switch (class) {
case GADGETUP: /* button released on a Gadget */
if (Intuimsg == (APTR)&gadQUIT) { /* "QUIT" */
goto signoff;
}
if (Intuimsg == (APTR)&gadFROMX10) { /* UP-LOAD */
Eventnum = 0;
if (Changed)
savedata();
standby(1);
if ((n = upload()) != 0) {
if (n != -1) /* if -1, msg was done by upload() */
yesyes("Error reading events from CP2910 (X10)");
}
++Changed;
standby(0);
break;
}
if (Intuimsg == (APTR)&gadEARLIER) { /* EARLIER */
if (Eventnum == 0)
pleasemodule();
else {
x = Events[Eventnum].xstart;
if (validspan(Eventnum,
--x, Events[Eventnum].xstop) == 0) {
RenderOneEvent(-1, Eventnum, NULL);
Events[Eventnum].xstart = x;
--Events[Eventnum].xstop;
RenderOneEvent(RED, Eventnum, NULL);
info(0);
++Changed;
}
else
printf("validspan=%d\n",
validspan(Eventnum,x, Events[Eventnum].xstop));
}
break;
}
if (Intuimsg == (APTR)&gadLATER) { /* LATER */
if (Eventnum == 0)
pleasemodule();
else {
x = Events[Eventnum].xstop;
if (validspan(Eventnum,
Events[Eventnum].xstart, ++x) == 0) {
RenderOneEvent(-1, Eventnum, NULL);
++Events[Eventnum].xstart;
Events[Eventnum].xstop = x;
RenderOneEvent(RED, Eventnum, NULL);
info(0);
++Changed;
}
}
break;
}
if (Intuimsg == (APTR)&gadLONGER) { /* LONGER */
if (Eventnum == 0)
pleasemodule();
else {
x = Events[Eventnum].xstop;
if (validspan(Eventnum,
Events[Eventnum].xstart, ++x) == 0) {
RenderOneEvent(-1, Eventnum, NULL);
Events[Eventnum].xstop = x;
RenderOneEvent(RED, Eventnum, NULL);
info(0);
++Changed;
}
}
break;
}
if (Intuimsg == (APTR)&gadSHORTER) { /* SHORTER */
if (Eventnum == 0)
pleasemodule();
else {
x = Events[Eventnum].xstop;
if (validspan(Eventnum,
Events[Eventnum].xstart, --x) == 0) {
RenderOneEvent(-1, Eventnum, NULL);
Events[Eventnum].xstop = x;
RenderOneEvent(RED, Eventnum, NULL);
info(0);
++Changed;
}
}
break;
}
if (Intuimsg == (APTR)&gadTOX10) { /* DOWN-LOAD */
standby(1);
if ((n = download()) != 0)
notresponding(n);
standby(0);
break;
}
if (Intuimsg == (APTR)&gadNEXT) { /* "NEXT" */
if (Eventnum) {
Eventnum = successor(Eventnum);
RenderOneDevice(Devnum);
info(0);
setdategadgets();
}
else
pleasemodule();
break;
}
if (Intuimsg == (APTR)&gadX10COMMAND) { /* X10COMMAND */
if (Eventnum) {
standby(1);
if ((n = x10command()) != 0)
notresponding(n);
standby(0);
}
else
pleasemodule();
break;
}
if (Intuimsg == (APTR)&gadSETNAME) { /* "SET NAME" */
if (Eventnum)
setname();
else
pleasemodule();
break;
}
if (Intuimsg == (APTR)&gadSETBASE) { /* "SET BASE" */
if (yesno(" Erases Displayed Events! ")) {
if (setbase() == 0) { /* get new Basecode */
purge(); /* erase all */
Eventnum = 0;
TimeGraticule();
info(0);
setdategadgets();
}
}
break;
}
if (Intuimsg == (APTR)&gadDEL) { /* "DELETE" */
if (Eventnum) {
DeleteEvent(Eventnum);
info(0);
setdategadgets();
}
else
pleasemodule();
break;
}
if (Intuimsg == (APTR)&gadX10DATE) { /* "SET DATE" */
standby(1);
x10date();
standby(0);
break;
}
if (Intuimsg == (APTR)&gadON) { /* "ON" */
if (Eventnum) {
++Changed;
Events[Eventnum].command = bsrON;
info(0);
}
else
pleasemodule();
break;
}
if (Intuimsg == (APTR)&gadOFF) { /* "OFF" */
if (Eventnum) {
++Changed;
Events[Eventnum].command = bsrOFF;
info(0);
}
else
pleasemodule();
break;
}
if (Intuimsg == (APTR)&gadDIMUP) { /* "BRIGHTER" */
if (Eventnum) {
++Changed;
Events[Eventnum].command = bsrDIM;
n = --Events[Eventnum].dimness;
if (n < 0)
Events[Eventnum].dimness = 0;
info(0);
}
else
pleasemodule();
break;
}
if (Intuimsg == (APTR)&gadDIMDN) { /* "DIMMER" */
if (Eventnum) {
Events[Eventnum].command = bsrDIM;
++Changed;
n = ++Events[Eventnum].dimness;
if (n >= 16 )
Events[Eventnum].dimness = 15;
info(0);
}
else
pleasemodule();
break;
}
if (Intuimsg == (APTR)&gadNEWFILE) { /* "NEW FILE" */
if (Changed)
savedata();
goto top;
}
if (Intuimsg == (APTR)&gadSECURITY) { /* "SECURITY" */
if (Eventnum == 0)
pleasemodule();
else {
Events[Eventnum].flags ^= SECURITY;
setdategadgets();
++Changed;
}
break;
}
if (Eventnum) {
/* If there is a selected event, and if the
user clicks on a day-name, then that day's
enable bit is toggled in the event data. */
if (Intuimsg == (APTR)&gadMON) j = 1;
else if (Intuimsg == (APTR)&gadTUES) j = 2;
else if (Intuimsg == (APTR)&gadWED) j = 4;
else if (Intuimsg == (APTR)&gadTHURS) j = 8;
else if (Intuimsg == (APTR)&gadFRI) j = 16;
else if (Intuimsg == (APTR)&gadSAT) j = 32;
else if (Intuimsg == (APTR)&gadSUN) j = 64;
else if (Intuimsg == (APTR)&gadWEEKDAYS)j = 0x1F;
else if (Intuimsg == (APTR)&gadWEEKEND) j = 0x60;
else j = 0;
if (j) {
RenderOneEvent(-1, Eventnum, NULL);
i = Events[Eventnum].days;
if ((i ^= j) != 0) { /* preclude NO days */
Events[Eventnum].days = i;
info(0);
setdategadgets();
RenderOneEvent(RED, Eventnum, NULL);
++Changed;
}
else
yesyes("That would select NO Days!");
}
}
break;
case CLOSEWINDOW: /* the system CLOSE WINDOW gadget */
signoff:
if (Changed)
savedata();
cleanup();
exit(0);
case MOUSEBUTTONS: /* Not a gadget, clicked on a pixel */
if (code == SELECTDOWN) { /* Button pressed down? */
if (mousey <= DevAreaY && mousey >= Yorg) {
/* clicked in top half, where events are drawn */
if (Eventnum) /* undraw RED one, if any */
RenderOneEvent(0, Eventnum, devicenames[Devnum]);
i = Devnum; /* previous device # */
Devnum = (mousey-Yorg) / barsize; /* new device no. */
if (mousex > xmax) { /* clicked on right side? */
if (i == Devnum)
Eventnum = successor(Eventnum);
else
Eventnum = listhead(Devnum);
info(0);
setdategadgets();
RenderOneEvent(RED,Eventnum,devicenames[Devnum]);
}
else if (mousey >= Yorg) {
/* clicked on left side...on an event line? */
Eventnum = listhead(Devnum);
while (Eventnum)
if (mousex >= Events[Eventnum].xstart &&
mousex <= Events[Eventnum].xstop )
break;
else
Eventnum = Events[Eventnum].link;
if (Eventnum == 0)
AddEvent(); /* another event this dev */
info(0);
setdategadgets();
RenderOneEvent(RED,Eventnum,devicenames[Devnum]);
}
}
}
break;
default:
if (Eventnum) {
RenderOneEvent(0, Eventnum, devicenames[Devnum]);
setdategadgets();
info(0);
Eventnum = Devnum = 0;
break;
}
} /* switch */
} /* for */
return(0);
}
/* ================================================================= */
validspan(event, startx, stopx)
register int event, startx, stopx;
{
register int n;
int dev;
if (startx > stopx)
return(-1);
if (stopx > xmax)
return(-3);
if (startx <= 0)
return(-5);
n = Events[event].link; /* n = next event, if any */
if (n)
if (stopx >= Events[n].xstart)
return(-7);
dev = Events[event].devicecode; /* find preceeding event, if any */
n = devicelist[dev];
while (n) {
if (Events[n].link == event) {
if (startx <= Events[n].xstop)
return(-11); /* bumped into left-hand neighbor */
break; /* it's OK */
}
n = Events[n].link;
}
return(0);
}
/* ================================================================= */
pleasemodule()
{
yesyes("Please Click On An Event or a Module Number.");
return(0);
}
/* ================================================================= */
/** This table converts unit number 1..8 or 9..16
to a bit flag, per X10 manual. Index with (1 <= n <= 8) */
SHORT unitcode[] = {
0, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x1
};
download()
{
register int unit, i, n, t;
int dev, eventnum;
register char *p;
if (Eventnum)
RenderOneEvent(0, Eventnum, devicenames[Devnum]); /* unRED display */
Eventnum = Devnum = 0;
info(0);
if (Changed)
savedata();
X10cmd[17] = 0; /* base housecode & reset interface */
X10cmd[18] = Housecodes[BaseHouseCode]; /* housecode */
x10out(&X10cmd[1],18);
if (getack() < 0)
return(-1);
eventnum = 0;
purgex10(); /* purge pending input data */
for (dev = 1; dev <= deviceMax; ++dev) { /* usually, 32 devices */
n = devicelist[dev]; /* event number 1..128 */
if (n == 0)
continue; /* skip all this code for unused dev's */
p = &devicenames[dev][0];
X10cmd[17] = 3; /* event/graphics download */
for (i = 0; i <= 7; ++i) {
t = ((dev-1) * 8) + i; /* graphics object # 0..256 */
X10cmd[18] = t << 1;
X10cmd[19] = (t >> 7) + 4; /* see page 25 of X10 manual */
if (*p < 0x20 || *p > 0x7f)
X10cmd[20] = 0x20;
else
X10cmd[20] = *p;
X10cmd[21] = *++p;
++p;
/* if (verbose)
printf("dnload dev %d's dev name; cmd=%02X %02X %02X %02X %02X\n",
dev, X10cmd[17],X10cmd[18],X10cmd[19],X10cmd[20],X10cmd[21]);
*/ x10out(&X10cmd[1], 22); /* download 2 chars of devicename */
/* The controller doesn't ACK this command */
}
unit = ((dev-1) % 16) + 1;
t = (dev-1) / 16;
X10cmd[26] = Housecodes[t + BaseHouseCode];
if (unit <= 8)
X10cmd[24] = unitcode[dev];
else
X10cmd[24] = 0;
if (unit > 8)
X10cmd[25] = unitcode[unit - 8];
else
X10cmd[25] = 0;
/*** do all events for the current device */
while (n) {
sprintf(scratchbuf, "Sending Device #%d, event #%d", dev, n);
appease(scratchbuf);
/** Compose command for start of event */
++eventnum;
X10cmd[18] = eventnum << 3; /* see pg 21 of X10 manual */
X10cmd[19] = eventnum >> 5; /* n must be <= 128 */
if (Events[n].flags & SECURITY)
X10cmd[20] = 9; /* normal vs. security mode */
else
X10cmd[20] = 8;
X10cmd[21] = Events[n].days;
t = Events[n].xstart * minutesK;
X10cmd[22] = t / 60; /* hours */
X10cmd[23] = t % 60; /* minutes */
X10cmd[27] = (Events[n].dimness << 4) | Events[n].command;
t = 0;
for (i = 20; i <= 27; ++i) { /* compute checksum per X10 manual */
t += X10cmd[i];
}
X10cmd[28] = t;
x10out(&X10cmd[1], 28); /* download this activity */
if (getack() < 0)
return(-1);
/*** If event just sent is not an OFF command then
create and send an OFF command to match the command
just downloaded. This is because OFF events are not
stored herein, unless they are special; explicitly defined.
***/
if ( (Events[n].command != bsrOFF) ) {
/*** 6/20/91 ***/
#if 0
printf("dev=%d n=%d Events[n].xstop=%d Events[Events[n].link].xstart=%d\n",
dev, n, Events[n].xstop, Events[Events[n].link].xstart);
#if 1
if (Events[n].link &&
((Events[Events[n].link].xstart -
Events[n].xstop) == 1))
goto ADJACENCY;
#endif
#endif
++eventnum;
X10cmd[18] = eventnum << 3;
X10cmd[19] = eventnum >> 5;
t = Events[n].xstop * minutesK;
X10cmd[22] = t / 60; /* hours */
X10cmd[23] = t % 60; /* minutes */
X10cmd[27] = bsrOFF;
t = 0;
for (i = 20; i <= 27; ++i) /* compute checksum per X10 manual */
t += X10cmd[i];
X10cmd[28] = t;
x10out(&X10cmd[1], 28); /* download event # n-1 */
if (getack() < 0)
return(-1);
}
ADJACENCY:
n = Events[n].link; /* next event, this device */
} /* while (linked list for dev N) */
}
return(0);
}
/* ======== Erase all stored events ============ */
purge()
{
register int i;
Eventnum = Devnum = Changed = 0;
for (i = 0; i <= deviceMax; ++i) {
devicenames[i][0] = '\0';
devicelist[i] = 0;
}
for (i = 0; i <= recordlimit; ++i)
Events[i].link = Events[i].devicecode = 0;
return(0);
}
/* ======== Retrieve Event Data & Dev. Names From X10 Box ================= */
upload()
{
register int i, n, t;
int dev = 0, eventnum = 1, x10counter = 0;
int prevcmd = -1, prevdev = -1, thiscmd, thisdev, x10byte, icon;
UBYTE *p, x10reply[32];
appease("Requesting Data from CP290");
purge(); /* purge all events */
TimeGraticule();
info(0);
purgex10(); /* scrub pending serial input */
X10cmd[17] = 5; /* request events, see page 31 of X10 manual */
x10out(&X10cmd[1], 17); /* event # n-1 */
Delay(50);
/*** read and discard leading sync and the status byte */
do {
if ( (n = x10inbyte()) < 0) {
notresponding(n);
return(-1);
}
}
while (n == 0xff); /* "status" is first byte other than 0xff */
/*** Read all uploaded events */
while (x10counter++ < 128) {
if ((n = x10inbyte()) < 0)
return(-2);
n &= 0xff;
if (n != 0xff) { /* active event? */
x10reply[1] = n; /* dupe. 1st byte */
for (i = 2; i <= 8; ++i) { /* read an event */
if ((n = x10inbyte()) < 0)
return(-3);
x10reply[i] = n & 0xff;
}
sprintf(scratchbuf, "Receiving event #%d", eventnum);
appease(scratchbuf);
t = (x10reply[5] << 8) + x10reply[6]; /* bit map of unit codes */
dev = 16;
while ((t & 1) == 0) {
--dev;
if ((t >>= 1) == 0)
return(-4);
}
n = x10reply[7]; /* house code */
for (i = 1; i <= 16; ++i)
if (n == (int)Housecodes[i])
break; /* i = 1 If housecode == 0x60, etc. */
Events[eventnum].devicecode = dev + ((i-1) * 16); /* 1..32 */
if ((x10reply[1] & 0x0F) == 9)
Events[eventnum].flags |= SECURITY;
else
Events[eventnum].flags &= (~SECURITY);
Events[eventnum].dimness = (x10reply[8] >> 4) & 0x0F;
Events[eventnum].command = (x10reply[8] & 0x0F);
Events[eventnum].days = x10reply[2];
n = ((x10reply[3] * 60) + x10reply[4]) / minutesK;
if (n > xmax)
return(-5);
Events[eventnum].xstart = Events[eventnum].xstop = n;
thisdev = Events[eventnum].devicecode;
thiscmd = Events[eventnum].command;
/*** Throw away this uploaded event if
1) It is for same device as previous one, and
2) the previous event was NOT an OFF command, and
3) the current event IS an OFF event.
This discards the OFF event paired with some earlier event.
***/
if ( (prevdev == thisdev) /* use OFF part of last event */
&& (prevcmd != bsrOFF)
&& (thiscmd == bsrOFF) )
Events[eventnum -1].xstop = Events[eventnum].xstart;
else { /* create new event */
Events[eventnum].link = 0;
if ((n = devicelist[dev]) == 0)
devicelist[dev] = eventnum++; /* make head of list */
else {
while (Events[n].link)
n = Events[n].link;
Events[n].link = eventnum++; /* make tail of list */
}
}
prevdev = thisdev;
prevcmd = thiscmd;
}
}
purgex10(); /* scrub pending serial input */
X10cmd[17] = 6; /* request graphics data */
x10out(&X10cmd[1], 17);
while (x10inbyte() == 0xff) /* discard sync & status */
;
for (icon = 1; icon <= 256; ++icon) {
if (((icon-1) & 7) == 0) {
dev = (icon / 8) + 1;
sprintf(scratchbuf, "Receiving device name #%d", dev);
appease(scratchbuf);
p = &devicenames[dev][0];
}
if ((x10byte = x10inbyte()) < 0)
return(x10byte);
if (x10byte != 0xff) { /* vacant space? */
*p++ = x10byte; /* assign 2 bytes */
*p++ = (char) x10inbyte();
}
}
for (dev = 1; dev <= deviceMax; ++dev) /* truncate */
devicenames[dev][DEVNAMELEN-1] = '\0';
RenderAllEvents();
info(0);
setdategadgets();
return(0);
}
#if 0
/* ================================================================= */
sunset()
{
register int month, min, hhmm24;
char clockinfo[8];
getclk(clockinfo); /* See Lattice 4.0 page F110 */
month = (int)clockinfo[2];
hhmm24 = sunsettable[month-1] + (dsmonths[month] * 100);
min = (hhmm24 / 100) * 60; /* hour time minutes per hour */
min += hhmm24 % 60; /* minutes part */
return(min / minutesK); /* time as an offset in pixels along X */
}
#endif
/* ================================================================= */
int
x10command()
{
register int n, m;
X10cmd[17] = 1;
X10cmd[18] = Events[Eventnum].command;
X10cmd[18] |= (Events[Eventnum].dimness << 4);
n = (Events[Eventnum].devicecode -1) / 16;
X10cmd[19] = Housecodes[n+1];
if ((n = Events[Eventnum].devicecode) == 0) /* device 1..32 */
return(-2); /* should never be 0! */
n &= 15; /* n = device 1..16 */
if (n == 0)
n = 16;
m = 0x8000; /* see page 12 of X10 manual for bit alignment */
while (--n)
m >>= 1;
X10cmd[20] = m & 0xff;
X10cmd[21] = m >> 8;
X10cmd[22] = X10cmd[18] + X10cmd[19] + X10cmd[20] + X10cmd[21];
appease("Sending to CP290");
x10out(&X10cmd[1], 22);
n = getack();
if (n < 0)
return(0);
return(0);
}
/* ================================================================= */
int
notresponding(err)
int err;
{
char prompt[100];
sprintf(prompt, " The X10 CP290 Controller Is Not Responding! (%d) ", err);
return(yesyes(prompt));
}
/* ================================================================= */
int
getack() /* read the ACK response to a command */
{
register int x10reply;
do
if ((x10reply = x10inbyte()) < 0) {
notresponding(x10reply);
return(x10reply);
}
while (x10reply == 0xff); /* discard syncs */
return(x10reply); /* response should be 0 or 1 */
}
/* ================================================================= */
int
x10date()
{
register int n, x10byte;
char x10info[8], clockinfo[8], *dayis, basecode;
dateagain:
purgex10();
X10cmd[17] = 4; /* Request date */
x10out(&X10cmd[1], 17);
do {
x10byte = x10inbyte();
if (x10byte < 0) {
notresponding(x10byte);
return(x10byte);
}
}
while (x10byte & 0x80); /* strip leading syncs */
x10info[0] = x10byte; /* status byte */
for (n = 1; n <= 5; ++n) {
if ((x10byte = x10inbyte()) < 0) {
notresponding(x10byte);
return(x10byte);
}
x10info[n] = x10byte;
}
switch ((int)x10info[3]) {
case 0x40: dayis = "Sun";
break;
case 0x20: dayis = "Sat";
break;
case 0x10: dayis = "Fri";
break;
case 0x08: dayis = "Thu";
break;
case 0x04: dayis = "Wed";
break;
case 0x02: dayis = "Tue";
break;
case 0x01: dayis = "Mon";
break;
default: dayis = "???";
break;
}
switch ((int)x10info[4]) {
case 0x60: basecode = 'A';
break;
case 0xE0: basecode = 'B';
break;
case 0x20: basecode = 'C';
break;
case 0xA0: basecode = 'D';
break;
case 0x10: basecode = 'E';
break;
case 0x90: basecode = 'F';
break;
case 0x50: basecode = 'G';
break;
case 0xD0: basecode = 'H';
break;
case 0x70: basecode = 'I';
break;
case 0xF0: basecode = 'J';
break;
case 0x30: basecode = 'K';
break;
case 0xB0: basecode = 'L';
break;
case 0x00: basecode = 'M';
break;
case 0x80: basecode = 'N';
break;
case 0x40: basecode = 'O';
break;
case 0xC0: basecode = 'P';
break;
default: basecode = '?';
break;
}
sprintf(textbuf, "DATE: %s, %d:%02d (base-code:%c) - Change to Amiga's DATE?",
dayis, x10info[2], x10info[1], basecode);
if (yesno(textbuf)) {
getclk(clockinfo); /* See Lattice 4.0 page F110 */
X10cmd[17] = 2; /* set clock */
X10cmd[18] = clockinfo[5]; /* min */
X10cmd[19] = clockinfo[4]; /* hr */
switch ((int)clockinfo[0]) {
case 0: n = 0x40; /* Sunday */
break;
case 1: n = 0x01; /* Mon */
break;
case 2: n = 0x02; /* Tue */
break;
case 3: n = 0x04; /* Wed */
break;
case 4: n = 0x08; /* Thu */
break;
case 5: n = 0x10; /* Fri */
break;
case 6: n = 0x20; /* Sat */
break;
}
X10cmd[20] = n;
X10cmd[21] = X10cmd[18] + X10cmd[19] + X10cmd[20]; /* chksum */
x10out(&X10cmd[1], 21);
getack();
goto dateagain;
}
return(0);
}
/* ================================================================= */
int
yesno(p)
char *p;
{
register int w, result, save1;
save1 = colortable[WHITE];
colortable[WHITE] = DEEPBLUE;
LoadRGB4(ViewPortAddress(window), &colortable[0], 16);
ynmessage.IText = p;
w = (strlen(p) * 8) + 50;
if (w < 200)
w = 200;
if (yesyesflag == 0)
result = AutoRequest(window, &ynmessage, &yesmsg, &nomsg,
0, 0, w, 64);
else
result = AutoRequest(window, &ynmessage, &yesmsg, &yesmsg,
0, 0, w, 64);
colortable[WHITE] = save1;
LoadRGB4(ViewPortAddress(window), &colortable[0], 16);
return(result);
}
/* ================================================================= */
int
yesyes(p)
char *p;
{
register int result;
++yesyesflag;
result = yesno(p);
yesyesflag = 0;
return(result);
}
/* ================================================================= */
int
purgex10()
{
register int i;
for (i = 1; i <= 2; ++i) {
Delay(10);
while (x10inbyte() >= 0)
; /* purge pending data */
}
return(0);
}
/* ================================================================= */
int
x10out(buf, count) /* send a buffer to the X10 CP290 Interface Unit */
char *buf;
int count;
{
register int n;
register char *p = buf;
char emsg[80];
IORser.IOSer.io_Command = CMD_WRITE;
for (n = count; n > 0; --n) {
IORser.IOSer.io_Data = (APTR)p++;
IORser.IOSer.io_Length = 1;
if (error = DoIO(&IORser)) {
sprintf(emsg, "Serial Port WRITE error %d", error)
yesyes(emsg);
return(error);
}
Delay(1); /* X10 says delay between bytes (this is 1/50 of a sec) */
}
return(0);
}
/* ================================================================= */
static char onech;
int
x10inbyte() /* returns < 0 if error, else 8 bit reply data */
{
register int n, timeout = 5;
char prompt[100];
reread:
chkabort();
IORser.IOSer.io_Command = SDCMD_QUERY; /* See if data is available */
if ((n = DoIO(&IORser)) != 0) {
sprintf(prompt, " Serial Port Read Error: %d ", n);
yesyes(prompt);
return(-1);
}
if (IORser.IOSer.io_Actual != 0) {
IORser.IOSer.io_Command = CMD_READ;
IORser.IOSer.io_Length = 1;
IORser.IOSer.io_Data = (APTR)&onech;
if (DoIO(&IORser) != 0)
return(-2); /* return if I/O error */
}
else {
Delay(5); /* No data avail now, so delay and retry */
if (--timeout > 0)
goto reread;
return(-3);
}
n = onech & 255;
if (verbose)
printf("$%02X ",n);
return(n);
}
/* ================================================================= */
int
standby(on) /* prompt user to wait before taking next action */
int on;
{
if (on) {
standbywindow.Screen = screen;
if ((sbwindow = OpenWindow(&standbywindow)) == NULL)
return(-1);
sbRport = sbwindow->RPort;
}
else if (sbwindow != NULL) {
CloseWindow(sbwindow);
sbwindow = NULL;
sbRport = NULL;
}
return(0);
}
/* ================================================================= */
#define APPEASEMSGX 200
#define APPEASEMSGY 50
appease(msg)
char *msg;
{
char buf[80];
if (sbRport == NULL)
return(-1);
SetAPen(sbRport, GREY8);
intuitext.IText = buf;
intuitext.FrontPen = GOLD;
intuitext.DrawMode = JAM2;
sprintf(buf, " %-40s ", msg);
PrintIText(sbRport, &intuitext, APPEASEMSGX, APPEASEMSGY);
return(0);
}
/* ================================================================= */
int
setname()
{
nameinfo.Buffer = (UBYTE *)&devicenames[0];
strcpy(nameinfo.Buffer, &devicenames[Devnum]);
nameinfo.MaxChars = DEVNAMELEN;
if (requeststring(" Name of Appliance? "))
return(-1);
if (strlen(nameinfo.Buffer) == 0)
return(0);
RenderOneEvent(-1, devicelist[Devnum], devicenames[Devnum]); /* erase old string */
strcpy(&devicenames[Devnum], &devicenames[0]);
RenderOneEvent(RED, Eventnum, devicenames[Devnum]);
++Changed;
return(0);
}
/* ================================================================= */
int
setbase()
{
char housechar[2];
housechar[0] = BaseHouseCode-1 + 'A';
housechar[1] = '\0';
nameinfo.Buffer = (UBYTE *)&housechar;
nameinfo.MaxChars = 2;
nameinfo.BufferPos = 1;
nameinfo.Buffer[0] = housechar[0];
if (requeststring(" Base House Code? "))
return(-1);
if (strlen(nameinfo.Buffer) == 0)
return(-1);
housechar[0] = toupper(housechar[0]);
if (housechar[0] < 'A' || housechar[0] > 'P')
return(-1);
BaseHouseCode = 1 + (housechar[0] - 'A');
return(0);
}
/* ================================================================= */
int
requeststring(prompt)
char *prompt;
{
register struct Window *window1;
register struct MsgPort *intuiport;
register struct IntuiMessage *message;
register int signalflag;
APTR intuimsg;
int n, class, code;
gadNAMEmsg.IText = prompt;
nw1.Screen = screen;
n = (strlen(prompt) * 10);
if (n < nw1X)
n = nw1X;
nw1.Width = n+16;
nameinfo.BufferPos = strlen(nameinfo.Buffer);
if ((window1 = OpenWindow(&nw1)) != NULL) {
ActivateGadget(&gadNAME, window1, NULL);
intuiport = window1->UserPort;
signalflag = 1 << window1->UserPort->mp_SigBit;
Wait(signalflag);
message = GetMsg(intuiport);
intuimsg = (APTR)message->IAddress; /* for gadgets, points to gadget*/
class = message->Class;
code = message->Code;
ReplyMsg(message);
CloseWindow(window1);
if (class == CLOSEWINDOW)
return(-1);
}
return(0);
}
/* ================================================================= */
int
getfilename(prompt)
/* return: 0=have name; 1=blank name; 2=closed window; -1=abort requested */
char *prompt;
{
nameinfo.Buffer = scratchbuf;
strcpy(nameinfo.Buffer, datafilename);
nameinfo.MaxChars = sizeof(datafilename)-1;
/* get filename string. if user clicks on window close, ask QUIT? */
if (requeststring(prompt)) {
if (yesno(" QUIT? "))
return(-1); /* yes, abort */
else
return(2); /* no, don't quit, but don't have a name */
}
if (strlen(nameinfo.Buffer) == 0)
return(1); /* name length bad? */
strcpy(datafilename, nameinfo.Buffer);
return(0);
}
/* ================================================================= */
int
savedata()
{
register int dev, n;
FILE *datafp = NULL;
while (datafp == NULL) {
if (yesno("Write Screen's Info. Into a File? ") == 0)
return(1);
if ((n = getfilename(" What file? ")) != 0)
return(n);
datafp = fopen(datafilename, "w");
}
for (dev = 1; dev <= deviceMax; ++dev) {
n = devicelist[dev];
while (n) {
fprintf(datafp, "%d,%d,%d,%d,%d,%d,%d\n",
Events[n].devicecode,
Events[n].xstart,
Events[n].xstop,
Events[n].days,
Events[n].command,
Events[n].dimness,
Events[n].flags);
n = Events[n].link;
}
}
fprintf(datafp, "0,0,0,0,0,0,0\n");
for (dev = 1; dev <= deviceMax; ++dev)
if (devicenames[dev][0] != '\0')
fprintf(datafp, "%d,\"%s\"\n", dev, &devicenames[dev]);
fclose(datafp);
Changed = 0;
return(0);
}
/* =================================================================
set the displayed day-of-week gadgets (MON, TUE...) to the On/Off
state as stored in the currently active event's "days" item. */
setdategadgets()
{
register struct Gadget *gad;
register int i, daybits;
gad = &gadMON; /* start of gadget list */
Daymask = daybits = Events[Eventnum].days;
for (i = 1; i <= 64; i *= 2) { /* each day ... */
setonegad(gad, (i & daybits) );
gad = gad->NextGadget;
}
setonegad(&gadSECURITY, Events[Eventnum].flags & SECURITY);
return(0);
}
/* ================================================================= */
setonegad(g, on)
struct Gadget *g;
int on;
{
register int oldsel, newsel;
oldsel = g->Flags;
if (on)
newsel = SELECTED;
else
newsel = 0;
g->Flags |= SELECTED;
if (oldsel != newsel)
RefreshGList(g, window, NULL, 1);
if (newsel == 0)
g->Flags &= (~SELECTED);
return(0);
}
/* ================================================================= */
int
info(device) /* display info for a given device code */
int device;
{
register int i, m, n;
int x, y,
t1,t2,
cmd,
color,
eventdays,
lnum = infoline+1;
char *p, *p1, dimmsg[8];
SetBPen(Rport, BLACK);
Daymask = Events[Eventnum].days;
if (device == 0) {
if (Devnum == 0)
n = 0;
else
n = devicelist[Devnum]; /* use currently selected one */
}
else
n = devicelist[device]; /* use caller's selected one */
/*** Print days of week, with Currently selected day(s) in PENTEXT1 */
p = "MTWTFSS";
x = infocol * charwidth;
y = (lnum -1) * charwidth;
for (i = 1; i <= 64; i *= 2) {
SetAPen(Rport, Daymask & i ? RED : GREEN);
Move(Rport, x, y);
Text(Rport, p++, 1);
x += 8;
}
/*** Print all events ocurring on the selected day(s) */
while (n) {
p = &textbuf[0];
if (n != Eventnum)
color = GREEN;
else
color = RED;
m = i = 1;
x = infocol * charwidth;
y = ((lnum -1) * charwidth) +1;
eventdays = Events[n].days;
/*** Draw a box for those days of the week
that the event is active */
while (i <= 0x40) {
if (eventdays & i)
SetAPen(Rport, DAYCOLOR0 + m - 1);
else
SetAPen(Rport, BLACK);
RectFill(Rport, x+2, y+2, x+6, y+6);
x += 8;
i *= 2;
++m;
}
/*** This code displays the start/stop times for an event */
SetAPen(Rport, color);
t1 = Events[n].xstart * minutesK;
t2 = Events[n].xstop * minutesK;
cmd = Events[n].command;
if (cmd == bsrDIM)
sprintf(p1 = dimmsg, "%2d", 16 - Events[n].dimness);
else
p1 = " ";
sprintf(p, " %02d:%02d\-%02d:%02d %s%s",
t1 / 60, t1 % 60, t2 / 60, t2 % 60, bsr[cmd], p1);
Move(Rport, x+8, lnum * charwidth);
Text(Rport,textbuf,strlen(p));
++lnum;
n = Events[n].link;
}
/*** Erase to end of screen */
SetAPen(Rport, BLACK);
RectFill(Rport, infocol * charwidth, ((lnum-1) * charwidth) +1, 638, 398);
return(0);
}
/* ================================================================= */
int
DeleteEvent(eventno)
int eventno;
{
register int n;
if (eventno == 0) {
pleasemodule();
return(-1);
}
++Changed;
n = devicelist[Devnum]; /* n = head of list */
RenderOneEvent(-1, eventno, NULL); /* erase RED event */
if (n == eventno) {
if (Events[eventno].link == 0) { /* deleteing sole member of list? */
RenderOneEvent(0, eventno, devicenames[Devnum]); /* unRED dev name */
RenderOneEvent(-1, eventno, NULL); /* erase event */
}
devicelist[Devnum] = Events[eventno].link; /* delete at head of list*/
}
else {
while (Events[n].link != eventno) { /* find predecessor event */
if (n == 0) {
yesyes("Predecessor link error");
cleanup();
exit(1); /* corrupted list */
}
n = Events[n].link;
}
Events[n].link = Events[eventno].link; /* delete within list */
}
Eventnum = successor(Events[eventno].link); /* update selected event no. */
Events[eventno].devicecode = 0; /* mark node as unused */
if (Eventnum == 0)
Eventnum = listhead(Devnum);
if (Eventnum)
RenderOneDevice(Devnum); /* put new RED on display */
hourlines();
return(0);
}
/* ================================================================= */
int
AddEvent()
{
register int n;
int t, predn, xlimit;
register int node, x;
++Changed;
node = 0;
while (Events[++node].devicecode != 0)
; /* nothing, find an unused node */
Events[node].devicecode = Devnum;
Events[node].xstart = mousex;
Events[node].xstop = mousex;
Events[node].link = 0;
Events[node].command = bsrON;
Events[node].days = 0x7F;
Events[node].flags = 0;
Eventnum = node;
xlimit = xmax;
x = mousex;
n = devicelist[Devnum]; /* head of list */
predn = 0;
while (n) { /* find non-overlapping limit for this event */
t = Events[n].xstart;
if (xlimit > t && x < t)
xlimit = t -1;
predn = n;
n = Events[n].link;
}
if (n == devicelist[Devnum]) { /* empty list or insert at head of list */
Events[node].link = n;
devicelist[Devnum] = node;
}
else { /* insert within list */
t = Events[predn].link;
Events[predn].link = node;
Events[node].link = t;
}
RenderOneEvent(RED, node, devicenames[Devnum]);
do {
if (x - window->MouseX) {
RenderOneEvent(-1, node, NULL);
x = window->MouseX;
if (x < Events[node].xstart)
x = Events[node].xstart;
if (x > xlimit)
x = xlimit;
Events[node].xstop = x;
RenderOneEvent(RED, node, NULL);
}
Delay(1);
}
while ((SetSignal(0,0) & Signalflag) == 0); /* mouse button UP Message */
Wait(Signalflag);
Message = GetMsg(Intuiport);
ReplyMsg(Message);
hourlines();
return(0);
}
/* ================================================================= */
int
RenderAllEvents()
{
register int i;
for (i = 1; i <= deviceMax; ++i)
RenderOneDevice(i);
info(0);
return(0);
}
/* ================================================================= */
int
RenderOneDevice(devno)
{
register int j, h, e;
e = 0;
h = j = devicelist[devno];
while (j) {
if (j == Eventnum)
e = j;
RenderOneEvent(0, j, NULL);
j = Events[j].link;
}
if (e)
RenderOneEvent(RED, e, devicenames[devno]); /* draw red one last! */
else
RenderOneEvent(0, h, devicenames[devno]); /* show name */
return(0);
}
/* ================================================================= */
int
RenderOneEvent(color, event, name) /* draw event lines for active days */
int color, event;
char *name;
{
register int y, day, dayflag, eventdays;
int device;
if (event == 0)
return(-1);
/* show the device name in proper color */
device = Events[event].devicecode - 1; /* device no. 0..n */
y = ((device+1) * barsize) + Yorg;
if (color <= 0)
intuitext.FrontPen = DEVNAMECOLOR; /* normal color */
else
intuitext.FrontPen = color; /* could be RED or TIMEFILLCOLOR */
if (name) { /* if head of list */
intuitext.IText = textbuf;
intuitext.DrawMode = JAM1;
sprintf(textbuf, "%c%d %s",
('A'-1)+BaseHouseCode+(device/16), (device & 15) + 1, name);
PrintIText(Rport, &intuitext, xmax+1, y);
}
if (color < 0) {
SetAPen(Rport, TIMEFILLCOLOR);
RectFill(Rport, Events[event].xstart, y, Events[event].xstop, y+6);
return(0);
}
dayflag = 1;
eventdays = Events[event].days;
for (day = 0; day < 7; ++day) {
if (eventdays & dayflag) {
if (color >= 0)
SetAPen(Rport, color ? color : DAYCOLOR0 + day);
Move(Rport, Events[event].xstart, y+day);
Draw(Rport, Events[event].xstop, y+day);
}
dayflag *= 2;
}
return(0);
}
/* ================================================================= */
/*** Draw the regions for the events for each X10 device
and show the device name as found in the disk file */
int
TimeGraticule()
{
register int device, x, y;
DevAreaY = (deviceMax * barsize) + Yorg; /* smaller numbers are dev area */
/* Erase the event display area of screen */
xmax = HourSpacing * 24;
SetAPen(Rport, BLACK);
RectFill(Rport, 8,Yorg, nw.MaxWidth-2, DevAreaY);
/* Draw horizontal box for each possible X10 device # and
print the textual name of each device, as found in the data file. */
intuitext.FrontPen = DEVNAMECOLOR;
intuitext.DrawMode = JAM1;
intuitext.IText = &textbuf[0];
for (device = 0; device < deviceMax; ++device) {
y = ((1+device) * barsize) + Yorg;
SetAPen(Rport, TIMEFILLCOLOR);
RectFill(Rport, 2, y, nw.MaxWidth, y+barheight);
sprintf(textbuf, "%c%d %s",
('A'-1)+BaseHouseCode+(device/16),
(device & 15) + 1, &devicenames[device+1]);
PrintIText(Rport, &intuitext, xmax+1, y);
}
/* Draw AM/PM legends on display */
y = DevAreaY + 16;
intuitext.FrontPen = TIMELINECOLOR;
intuitext.IText = "AM";
PrintIText(Rport, &intuitext, 0, y);
intuitext.IText = "PM";
PrintIText(Rport, &intuitext, 13*HourSpacing, y);
intuitext.IText = "N";
PrintIText(Rport, &intuitext, (12 * HourSpacing) + 2, y);
x = 12 * HourSpacing;
SetAPen(Rport,TIMELINECOLOR);
Move(Rport, 20, y+4);
Draw(Rport, x-2, y+4);
Move(Rport, 14 * HourSpacing, y+4);
Draw(Rport, 24 * HourSpacing, y+4);
hourlines(); /* add the vertical hour lines */
return(0);
}
/* ================================================================= */
/*** Draw 24 lines vertically, depicting 24 hours/day */
static int hrlineflag = 1;
int
hourlines()
{
register int y, hour, x, hh;
intuitext.IText = &textbuf[0];
intuitext.FrontPen = TIMELINECOLOR;
intuitext.DrawMode = JAM1;
y = DevAreaY + 10;
x = 0;
hh = 0;
for (hour = 0; hour <= 24; ++hour) {
SetAPen(Rport, TIMELINECOLOR);
Move(Rport, x, barsize);
Draw(Rport, x, y);
if (hrlineflag && hh) {
sprintf(textbuf, "%2d", hh);
PrintIText(Rport, &intuitext, x - 8, y);
}
x += HourSpacing;
if (++hh > 12)
hh = 1;
}
hrlineflag = 0;
return(0);
}
/* ================================================================= */
/*** Terminate program housekeeping */
int
cleanup()
{
if (myplane)
FreeRaster(myplane,TMPRASX,TMPRASY);
if (window)
CloseWindow(window);
if (screen)
CloseScreen(screen);
if (IntuitionBase)
CloseLibrary(IntuitionBase);
if (GfxBase)
CloseLibrary(GfxBase);
if (Serialisopen) {
DeletePort( IORser.IOSer.io_Message.mn_ReplyPort );
CloseDevice( &IORser );
}
return(0);
}
/* ================================================================= */
/* return next in list for given day mask */
successor(eventno)
int eventno;
{
register int n;
if ( (n = Events[eventno].link) == 0)
return(listhead(Events[eventno].devicecode));
#ifdef DAYMASK
while ( (Events[n].days & Daymask) == 0)
if ( (n = Events[n].link) == 0)
break;
#endif
return(n);
}
/* ================================================================= */
/* Return 1st in list for given day mask */
listhead(devno)
int devno;
{
register int n;
n = devicelist[devno];
#ifdef DAYMASK
while (n)
if (Events[n].days & Daymask)
break;
else
n = Events[n].link;
#endif
return(n);
}